import { Context } from "koa";
import bemModel from "../models/backEndManagement";
import bemRoleModel from "../models/bemrole";
import bemBtnRoleModel from "../models/btnrole";
import { validate } from "../utils/validate";
import { Rules } from "async-validator";
import { sign, refreshSign, verify, resVerify } from "../utils/auth";
import { resp } from "../utils/res";
import { comparecrypt } from "../utils/bcryptjs";
import { findByProps } from "../utils/crud";
import mongoose from "mongoose";
import menuesModel from "./../models/menues";
class BEM {
  async getCode(ctx: Context) {
    let code = Math.random().toString(36).substring(8);
    resp.success(ctx, { code: code });
  }
  async register(ctx: Context) {
    const rules: Rules = {
      phone: [
        {
          type: "string",
          required: true,
          pattern: /^1[3456789]\d{9}$/,
          message: "手机号校验错误",
        },
      ],
      password: [
        {
          type: "string",
          required: true,
          message: "请输入密码",
        },
      ],
    };
    type DATA = {
      phone: string;
      password: string;
    };
    const { data, error } = await validate<DATA>(ctx, rules);
    if (error) {
      return resp.error(ctx, error);
    } else {
      try {
        let res = await bemModel.findOne({ phone: data.phone });
        if (res) {
          resp.error(ctx, "此手机号已注册");
        } else {
          try {
            await bemModel.create({
              phone: data.phone,
              password: data.password,
              username: Math.random().toString(36).substring(2) + Date.now(),
              role: data.phone == "17516211205" ? "超级管理员" : "普通用户",
              btnrole:
                data.phone == "17516211205"
                  ? [
                    "add",
                    "delete",
                    "alldelete",
                    "distribute",
                    "refresh",
                    "modify",
                  ]
                  : [],
            });
            resp.success(ctx, [], "注册成功!");
          } catch (error) {
            resp.error(ctx, JSON.stringify(error));
          }
        }
      } catch (error) {
        resp.error(ctx, JSON.stringify(error));
      }
    }
  }
  async delusers(ctx: Context) {
    const rules: Rules = {
      ids: [
        {
          type: "string",
          required: true,
          message: "未传入删除_id数组",
        },
      ],
    };
    type DATA = {
      ids: string;
    };
    const { data, error } = await validate<DATA>(ctx, rules);
    if (error) {
      return resp.error(ctx, error);
    }
    let delRes = await bemModel.deleteMany({ _id: JSON.parse(data.ids) });
    if (delRes) {
      resp.success(ctx, {
        deleteIsSuccess: delRes.acknowledged,
        num: delRes.deletedCount,
      });
    }
  }
  async isOutData(ctx: Context) {
    let retoken = ctx.request.header.authorization?.split(" ")[1];
    if (!retoken) {
      return resp.error(ctx, "token为空", 400);
    }
    let vres = verify(retoken);
    if (vres.code == 200) {
      //retoken 验证成功 重新发送token
      resp.success(ctx, null);
    } else {
      resp.error(ctx, vres.data, vres.code || 201);
    }
  }
  async login(ctx: Context) {
    const rules: Rules = {
      phone: [
        {
          type: "string",
          required: true,
          pattern: /^1[3456789]\d{9}$/,
          message: "手机号校验错误",
        },
      ],
      password: [
        {
          type: "string",
          required: true,
          message: "请输入密码",
        },
      ],
    };
    type DATA = {
      phone: string;
      password: string;
    };
    const { data, error } = await validate<DATA>(ctx, rules);
    if (error) {
      return resp.error(ctx, error);
    } else {
      try {
        let findByPropsRes = await findByProps(bemModel, {
          phone: data.phone,
        });
        if (!findByPropsRes) {
          return resp.error(ctx, "该手机号未注册");
        } else {
          if (comparecrypt(data.password, findByPropsRes.password)) {
            let signRes = sign({
              phone: data.phone,
              id: findByPropsRes._id,
            });
            let refreshSignRes = refreshSign({
              phone: data.phone,
              id: findByPropsRes._id,
            });
            delete findByPropsRes._doc.password;
            // delete findByPropsRes._doc._id;
            delete findByPropsRes._doc.__v;
            delete findByPropsRes._doc.phone;
            resp.success(
              ctx,
              {
                token: signRes,
                refresh_token: refreshSignRes,
                userinfo: findByPropsRes,
              },
              "登录成功"
            );
          } else {
            return resp.error(ctx, "密码错误");
          }
        }
      } catch (error: any) {
        console.log('====================================');
        console.log(error);
        console.log('====================================');
        return resp.error(ctx, JSON.stringify(error));
      }
    }
  }
  async getuserinfo(ctx: Context) {
    let token = ctx.request.header.authorization?.split(" ")[1];
    if (!token) {
      return resp.error(ctx, "token为空");
    }
    let vres = verify(token);
    if (vres.code == 200) {
      let res = await bemModel.findById(vres.data.id, {
        password: 0,
        __v: 0,
        phone: 0,
      });
      if (res) {
        resp.success(ctx, { userinfo: res });
      } else {
        resp.error(ctx);
      }
    } else {
      resp.error(ctx, vres.data as string);
    }
  }
  async reGetToken(ctx: Context) {
    let retoken = ctx.request.header.authorization?.split(" ")[1];
    if (!retoken) {
      return resp.error(ctx, "token为空");
    }
    let vres = resVerify(retoken);
    if (vres.code == 200) {
      //retoken 验证成功 重新发送token
      let signRes = sign({
        phone: vres.data.phone,
        id: vres.data.id,
      });
      let refreshSignRes = refreshSign({
        phone: vres.data.phone,
        id: vres.data.id,
      });
      resp.success(ctx, {
        token: signRes,
        refresh_token: refreshSignRes,
      });
    } else {
      resp.error(ctx, vres.data as string);
    }
  }
  async routertest(ctx: Context) {
    let token = ctx.request.header.authorization?.split(" ")[1];
    if (!token) {
      return resp.error(ctx, "token为空");
    }
    let vres = verify(token);
    if (vres.code == 200) {
      const loginRouterInfo = await bemModel.aggregate([
        {
          $lookup: {
            from: "bemrolemodels", // 关联 userinfo 表
            localField: "role", // 根据 dailyModel 里 userid 字段查询
            foreignField: "rolename", // 查找 userinfos 表里对应的 _id 的数据
            as: "router", // 返回的字段别名
          },
        },
        {
          $match: {
            _id: new mongoose.Types.ObjectId(vres.data.id),
          },
        }, //过滤条件
        {
          $project: {
            __v: 0,
            _id: 0,
            phone: 0,
            username: 0,
            role: 0,
            avator: 0,
            password: 0,
          },
        },
      ]);
      if (loginRouterInfo) {
        resp.success(ctx, {
          routers: loginRouterInfo[0]?.router[0]?.role || [
            "/home",
            "/roles",
            "/roleslist",
            "/rolelist",
            "/roleuser",
          ],
        });
      } else {
        resp.error(ctx);
      }
    } else {
      resp.error(ctx, vres.data as string);
    }
  }
  async putuserinfo(ctx: Context) {
    const rules: Rules = {
      username: [
        {
          type: "string",
        },
      ],
      avator: [
        {
          type: "string",
        },
      ],
      id: [
        {
          type: "string",
        },
      ],
      role: [
        {
          type: "string",
        },
      ],
      btnrole: [
        {
          type: "string",
        },
      ],
    };
    type DATA = {
      username: string;
      avator: string;
      id: string;
      role: string;
      btnrole: string;
    };
    const { data, error } = await validate<DATA>(ctx, rules);
    if (error) {
      return resp.error(ctx, error);
    }
    let token = ctx.request.header.authorization?.split(" ")[1];
    if (!token) {
      return resp.error(ctx, "token为空");
    }
    let vres = verify(token);
    if (vres.code == 200) {
      let res = await bemModel.findOneAndUpdate(
        { _id: data.id },
        {
          $set: {
            avator: data.avator,
            username: data.username,
            role: data.role,
            btnrole: data.btnrole ? JSON.parse(data.btnrole) : undefined,
          },
        },
        {
          new: true,
        }
      );
      if (res) {
        resp.success(ctx);
      } else {
        resp.error(ctx);
      }
    } else {
      resp.error(ctx, vres.data as string);
    }
  }
  async getuserlist(ctx: Context) {
    let usersList = await bemModel.find({}, { __v: 0 });
    if (usersList) {
      resp.success(ctx, usersList);
    } else {
      resp.error(ctx, "暂无用户数据");
    }
  }
  async addrolename(ctx: Context) {
    const rules: Rules = {
      rolename: [
        {
          type: "string",
          required: true,
        },
      ],
      role: [
        {
          type: "string",
        },
      ],
    };
    type DATA = {
      rolename: string;
      role: string;
    };
    const { data, error } = await validate<DATA>(ctx, rules);
    if (error) {
      return resp.error(ctx, error);
    }
    try {
      let res = await bemRoleModel.create({
        rolename: data.rolename,
        role: JSON.parse(data.role),
      });
      if (res) {
        resp.success(ctx, [], "添加成功");
      } else {
        resp.error(ctx, "添加失败");
      }
    } catch (err: any) {
      if (err.code == 11000) {
        resp.error(ctx, "角色名禁止重复");
      }
    }
  }
  async delrolename(ctx: Context) {
    const rules: Rules = {
      ids: [
        {
          type: "string",
          required: true,
        },
      ],
    };
    type DATA = {
      ids: string;
    };
    const { data, error } = await validate<DATA>(ctx, rules);
    if (error) {
      return resp.error(ctx, error);
    }
    let delRes = await bemRoleModel.deleteMany({ _id: JSON.parse(data.ids) });
    if (delRes) {
      resp.success(ctx, {
        deleteIsSuccess: delRes.acknowledged,
        num: delRes.deletedCount,
      });
    }
  }
  async getrolelist(ctx: Context) {
    let res = await bemRoleModel.find({}, { __v: 0 });
    if (res) {
      resp.success(ctx, res, "获取角色列表成功");
    } else {
      resp.error(ctx, "获取角色列表失败");
    }
  }
  async distribute(ctx: Context) {
    const rules: Rules = {
      id: [
        {
          type: "string",
          required: true,
        },
      ],
      role: [
        {
          type: "string",
        },
      ],
      rolename: [
        {
          type: "string",
        },
      ],
    };
    type DATA = {
      id: string;
      role: string;
      rolename: string;
    };
    const { data, error } = await validate<DATA>(ctx, rules);
    let token = ctx.request.header.authorization?.split(" ")[1];
    if (!token) {
      return resp.error(ctx, "token为空");
    }
    let vres = verify(token);
    if (vres.code == 200) {
      let subobj;
      if (data.role) {
        subobj = {
          role: JSON.parse(data.role),
          rolename: data.rolename,
        };
      } else {
        subobj = {
          rolename: data.rolename,
        };
      }
      if (error) {
        return resp.error(ctx, error);
      }
      try {
        let res = (await bemRoleModel.findByIdAndUpdate(data.id, subobj, {
          new: true,
        })) as any;
        if (res) {
          resp.success(ctx, [], "添加权限成功");
        } else {
          resp.error(ctx, "添加权限失败");
        }
      } catch (err: any) {
        if (err.code == 11000) {
          resp.error(ctx, "角色名禁止重复");
        }
      }
    } else {
      resp.error(ctx, vres.data as string);
    }
  }
  async createMenues(ctx: Context) {
    const rules: Rules = {
      name: [
        {
          type: "string",
        },
      ],
      icon: [
        {
          type: "string",
        },
      ],
      path: [
        {
          type: "string",
        },
      ],
      desc: [
        {
          type: "string",
        },
      ],
      //路由等级
      level: [
        {
          type: "number",
        },
      ],
      order: [
        {
          type: "number",
        },
      ],
      hidden: [
        {
          type: "boolean",
        },
      ],
      //父路由id
      parentId: [
        {
          type: "string",
        },
      ],
    };
    type DATA = {
      name: string;
      level: number;
      parentId: string;
      path: string;
      icon: string;
      desc: string;
      order: number;
      hidden: boolean
    };
    const { data, error } = await validate<DATA>(ctx, rules);
    if (error) {
      return resp.error(ctx, error);
    }
    const { name, level, parentId, path, icon, desc, order, hidden } = data;
    try {
      let res = (await menuesModel.create({
        name,
        level,
        path,
        parentId,
        icon,
        desc,
        order,
        hidden
      })) as any;
      resp.success(ctx, res, '路由添加成功');
    } catch (error: any) {
      if (error.code == 11000) {
        resp.error(ctx, '路由数据重复，请检查')
      }
    }

  }
  async getMenues(ctx: Context) {

    let res = await menuesModel.find();
    if (res.length == 0) {
      menuesModel
        .create({
          name: "顶级菜单",
          level: 0,
          path: "/xxx",
          parentId: 0,
        })
        .then((res) => {
 
          menuesModel
            .create({
              name: "菜单列表",
              level: 0,
              path: "menuslist",
              parentId: res._id,
              desc: 'menusView'
            })
            .then((ress) => {
              console.log("====================================");
              console.log("顶级菜单初始化成功");
              console.log("====================================");




            });


        });
    }



    let ress = res.map((e) => {
      return {
        label: e.name,
        _id: e._id,
        parentId: e.parentId,
        order: e.order
      };
    });

    function toTree(arr: any, parentId: any) {
      if (!arr.length) {
        return false;
      }
      // 定义一个 children 数组
      const children = [] as any;
      let narr = arr.sort((a: any, b: any) => b.order - a.order)
      for (const node of narr) {
        if (node.parentId == parentId) {
          const child = { ...node };
          // 对于每个匹配的子节点，递归调用 toTree 函数，传递当前子节点的 ID 作为新的父节点 ID，以获取当前子节点的所有子节点。
          let res = toTree(narr, node._id);
          if (res.length > 0) {
            child.children = toTree(narr, node._id);
          }
          children.push(child);
        }
      }
      return children;
    }
    let s = toTree(JSON.parse(JSON.stringify(res)), 0);
    let ss = toTree(JSON.parse(JSON.stringify(ress)), 0);
    resp.success(ctx, {
      list: s[0].children,
      parent0: ss,
    });
  }





  async getMenuesRoutes(ctx: Context) {
    type DATA = {
      name: string;
      level: number;
      parentId: string;
      path: string;
      icon: string;
    };
    let res = await menuesModel.find();




    // resp.success(ctx, res);
    function toTree(arr: any, parentId: any) {
      if (!arr.length) {
        return false;
      }
      // 定义一个 children 数组
      const children = [] as any;
      let narr = arr.sort((a: any, b: any) => b.order - a.order)
      for (const node of narr) {
        if (node.parentId == parentId) {
          const child = { ...node };
          // 对于每个匹配的子节点，递归调用 toTree 函数，传递当前子节点的 ID 作为新的父节点 ID，以获取当前子节点的所有子节点。
          let res = toTree(narr, node._id);
          if (res.length > 0) {
            child.children = toTree(narr, node._id);
          }
          children.push(child);
        }
      }
      return children;
    }



    let s = toTree(JSON.parse(JSON.stringify(res)), 0);
    resp.success(ctx, s[0]?.children);
  }









  async delMenues(ctx: Context) {
    const rules: Rules = {
      ids: [
        {
          type: "string",
          required: true,
        },
      ],
    };
    type DATA = {
      ids: string;
    };
    const { data, error } = await validate<DATA>(ctx, rules);
    if (error) {
      return resp.error(ctx, error);
    }
    let delRes = await menuesModel.deleteMany({ _id: data.ids });
    if (delRes) {
      resp.success(ctx, {
        deleteIsSuccess: delRes.acknowledged,
        num: delRes.deletedCount,
      }, '路由删除成功');
    }
  }





  async putMenues(ctx: Context) {
    const rules: Rules = {
      name: [
        {
          type: "string",
        },
      ],
      icon: [
        {
          type: "string",
        },
      ],
      path: [
        {
          type: "string",
        },
      ],
      desc: [
        {
          type: "string",
        },
      ],
      //路由等级
      level: [
        {
          type: "number",
        },
      ],
      order: [
        {
          type: "number",
        },
      ],
      hidden: [
        {
          type: "boolean",
        },
      ],
      //父路由id
      parentId: [
        {
          type: "string",
        },
      ],
      id: [
        {
          type: "string",
        },
      ]
    };
    type DATA = {
      name: string;
      level: number;
      parentId: string;
      path: string;
      icon: string;
      desc: string;
      order: number;
      hidden: boolean
      id: string
    };
    const { data, error } = await validate<DATA>(ctx, rules);
    if (error) {
      return resp.error(ctx, error);
    }
    const { name, level, parentId, path, icon, desc, order, hidden, id } = data;
    let token = ctx.request.header.authorization?.split(" ")[1];
    if (!token) {
      return resp.error(ctx, "token为空");
    }
    let vres = verify(token);
    if (vres.code == 200) {
      let res = await menuesModel.findOneAndUpdate(
        { _id: id },
        {
          $set: {
            name: name, level: level, parentId: parentId, path: path, icon: icon, desc: desc, order: order, hidden: hidden
          },
        },
        {
          new: true,
        }
      );
      if (res) {
        resp.success(ctx);
      } else {
        resp.error(ctx);
      }
    } else {
      resp.error(ctx, vres.data as string);
    }
  }
}
const bem = new BEM();
export default bem;
